package thirdweek;

import secondweek.EmptyCollectionException;

import java.util.Arrays;
import java.util.EmptyStackException;
import java.util.PrimitiveIterator;

public class CircularArrayQueue<T> implements QueueADT<T>{
    private final int DEFAULT_CAPACITY = 100;
    private int front, rear, count;
    private T[] queue;
    /**
     * Creatas an empty queue using the specified capacity.
     * @param initialCapacity the initial size of the circular array queue
     */
    public CircularArrayQueue(int initialCapacity){
        front = rear = count = 0;
        queue = ((T[])(new Object[initialCapacity]));
    }
    /**
     * Creates an empty queue using the default capacity.
     */
    public CircularArrayQueue(){
        front = rear = count = 0;
        queue = ((T[])(new Object[DEFAULT_CAPACITY]));
    }

    @Override
    public void enqueue(T element) {
        if(size() == queue.length)
            expandCapcity();

        queue[rear] = element;
        rear = (rear + 1) % queue.length;
        /*head和tail应该是存储该数组的下标而不是一个指向该数组元素的指针。如果tail是指针，那么 tail本质上是一个内存地址，*tail是指向该数组的某一元素。那么这算式tail = (tail + 1) % N其实是对某数组元素的内存地址+1，然后在用N求余。
所以head和tail应该是保存该数组的下标，而不是指向该数组元素的指针。*/

        count++;
    }

    /**
     * Create a new array to store the contents of this queue with twice the capacity of the old one.
     */
    public void expandCapcity(){
        T[] larger = (T[])(new Object[queue.length * 2]);
        for(int scan = 0; scan < count; scan++){
            larger[scan] = queue[front];
            front = (front + 1) % queue.length;
        }
        front = 0;
        rear = count;
        queue = larger;
    }

    /**
     * Removes the element at the front of the queue and returns a reference to it.
     * @return the element removed from the front of the queue
     * @throws an EmptyCollectionException if the queue is empty.
     */
    @Override
    public T dequeue() throws EmptyCollectionException {
        if(isEmpty())
            throw new EmptyCollectionException("queue");

        T result = queue[front];
        queue[rear] = null;
        front = (front + 1) % queue.length;

        count--;

        return result;
    }

    @Override
    public T first() {
        if(isEmpty())
            throw new EmptyCollectionException("queue");

        return queue[front];
    }

    @Override
    public boolean isEmpty() {
        if(front == rear)
            return true;
        else
            return false;
    }

    @Override
    public int size() {
        return count;
    }

    @Override
    public String toString() {
        String result ="";
        int temp = front;
        for(int num = 0; num < size(); num++) {
            result += queue[temp] + " ";
            temp = (temp + 1) % queue.length;
        }
        return result;
    }
}
